﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace Microsoft.WowAddonStudio.FrameXml.Formats.Blp
{
    internal class DxtMipMap : MipMap
    {
        private readonly BlpCompression compression;
        private readonly byte[] data;

        public DxtMipMap(Size size, byte[] data, BlpCompression compression)
            : base(size)
        {
            if (data == null)
                throw new ArgumentNullException("data");

            this.data = data;
            this.compression = compression;
        }

        /// <summary>
        /// Gets the mipmap as an <see cref="Image"/>.
        /// </summary>
        /// <returns></returns>
        public override Image GetImage()
        {
            // Decompress the image
            IntPtr uncompressedData = NativeMethods.DecompressImage(Size.Width, Size.Height, data, compression);
            
            // Draw the uncompressed data into the bitmap data
            if (uncompressedData != IntPtr.Zero)
            {
                try
                {
                    // Create a new bitmap of the correct size
                    var bitmap = new Bitmap(Size.Width, Size.Height, PixelFormat.Format32bppArgb);

                    // Lock the bitmap bits
                    BitmapData bitmapData = bitmap.LockBits(new Rectangle(Point.Empty, Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

                    // Draw the uncompressed data onto the bitmap
                    DxtMipMap.DrawData(bitmapData, uncompressedData);

                    // Unlock the bitmap bits
                    bitmap.UnlockBits(bitmapData);

                    // Return the bitmap
                    return bitmap;
                }
                finally
                {
                    // Free the memory allocated for the uncompressed data
                    Marshal.FreeHGlobal(uncompressedData);
                }
            }

            // Could not get image, return null
            return null;
        }

        private static unsafe void DrawData(BitmapData bitmapData, IntPtr uncompressedData)
        {
            int width = bitmapData.Width;
            int height = bitmapData.Height;

            // bitmapData is BGRA
            // decompressed data is RGBA

            IntPtr p_dest = bitmapData.Scan0;
            IntPtr p_src = uncompressedData;
            var rgba = new byte[4];

            fixed (byte* p_rgba = rgba)
            {
                for (int i = 0; i < width * height; i++)
                {
                    int pixel = Marshal.ReadInt32(p_src);

                    *((int*)p_rgba) = pixel;

                    byte t = p_rgba[2];

                    p_rgba[2] = p_rgba[0];
                    p_rgba[0] = t;

                    Marshal.WriteInt32(p_dest, *((int*)p_rgba));

                    p_src = new IntPtr(p_src.ToInt32() + 4);
                    p_dest = new IntPtr(p_dest.ToInt32() + 4);
                }
            }
        }
    }
}
